﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Noris.Tools.TraceVisualiser.Interface;
using Noris.Tools.TraceVisualiser.Support;
using Noris.Tools.TraceVisualiser.Forms;
using Noris.Tools.TraceVisualiser.Components;

namespace Noris.Tools.TraceVisualiser.TraceData
{
    internal class Func_TimeShift : Func_Base, IFunctionContextMenuItem
    {
        #region IPlugin Members
        /// <summary>
        /// Příznak, že Plugin je aktivní ve standardním běhu (tj. při běžném užiavtelském spuštění).
        /// Plně funkční pluginy tedy vrací true.
        /// Pluginy, které jsou ve vývoji, vrací false, takové jsou zobrazeny / spouštěny pouze v aplikaci, která běží v režimu Debug.
        /// </summary>
        bool IPlugin.Active { get { return true; } }
        #endregion
        #region IFunctionContextMenuItem Members
        bool IFunctionContextMenuItem.IsFunctionSuitableFor(FunctionContextMenuItemSuitableArgs args)
        {
            FunctionMenuItem mainItem = new FunctionMenuItem(80, "Eliminace časového posunu", 
				"Posune data podřízeného trace tak, aby korespondovaly na společné časové ose.",
				false, Noris.Tools.TraceVisualiser.Pics.PicLibrary16.AlignFillLeft_FromFile, null);
            // Neměnit čísla 10,20,30 : reaguje na ně výkonná metoda _SetTimeShift().
            mainItem.SubItems.Add(new FunctionMenuItem(10, "Shodný počátek", 
				"Zarovná časy počátku události",
				true, Noris.Tools.TraceVisualiser.Pics.PicLibrary16.AlignFillLeft_FromFile, null));
            mainItem.SubItems.Add(new FunctionMenuItem(20, "Zarovnat střed",
				"Zarovná časy středu události",
				true, Noris.Tools.TraceVisualiser.Pics.PicLibrary16.AlignFillCenter_FromFile, null));
            mainItem.SubItems.Add(new FunctionMenuItem(30, "Shodný konec",
				"Zarovná časy konce události",
				true, Noris.Tools.TraceVisualiser.Pics.PicLibrary16.AlignFillRight_FromFile, null));
			mainItem.SubItems.Add(new FunctionMenuItem(40, "-"));
			mainItem.SubItems.Add(new FunctionMenuItem(50, "Zrušit eliminaci",
				"Pro vybraný server zruší kompenzaci časového posunu",
				true, Noris.Tools.TraceVisualiser.Pics.PicLibrary16.DialogCancel3_FromFile, null));
			args.MenuItems.Add(mainItem);
            return true;
        }
        bool IFunctionContextMenuItem.IsMenuItemEnabledFor(FunctionContextMenuItemRunArgs args)
        {
			int menuOrder = (args.FunctionItem == null ? 0 : args.FunctionItem.MenuOrder);
			if (menuOrder == 10 || menuOrder == 20 || menuOrder == 30)
			{
				EventInfo fixedEvent, shiftEvent;
				return (this._GetEvents(args, out fixedEvent, out shiftEvent));
			}
			else if (menuOrder == 50)
			{
				EventInfo clickedEvent = this.GetEventInfo(args, args.ClickedItem);
				return (clickedEvent != null && clickedEvent.Server.ContainVisualOffset);
			}
			return false;
        }
        void IFunctionContextMenuItem.Run(FunctionContextMenuItemRunArgs args)
        {
            this._SetTimeShift(args);
        }
        #endregion
        #region Výkon funkce
        /// <summary>
        /// Nastaví časový posun pro událost shiftEvent podle události fixedEvent.
        /// </summary>
        /// <param name="args"></param>
        /// <param name="fixedEvent"></param>
        /// <param name="shiftEvent"></param>
        private void _SetTimeShift(FunctionContextMenuItemRunArgs args)
        {
            EventInfo fixedEvent, shiftEvent;
			bool containEvents = this._GetEvents(args, out fixedEvent, out shiftEvent);
			int menuOrder = (args.FunctionItem == null ? 0 : args.FunctionItem.MenuOrder);
			switch (menuOrder)
            {
                case 10:
                    // Begin
					if (containEvents)
					{
						shiftEvent.Server.SetVisualTime(shiftEvent.Time.Begin, fixedEvent.Time.Begin);
						args.Result.InvalidateAllElements = true;
					}
                    break;
                case 20:
                    // Center
					if (containEvents)
					{
						shiftEvent.Server.SetVisualTime(shiftEvent.Time.Center, fixedEvent.Time.Center);
						args.Result.InvalidateAllElements = true;
					}
                    break;
                case 30:
                    // End
					if (containEvents)
					{
						shiftEvent.Server.SetVisualTime(shiftEvent.Time.End, fixedEvent.Time.End);
						args.Result.InvalidateAllElements = true;
					}
                    break;
				case 50:
					// Clear:
					EventInfo clickedEvent = this.GetEventInfo(args, args.ClickedItem);
					if (clickedEvent != null)
					{
						clickedEvent.Server.ClearTimeShifts();
						args.Result.InvalidateAllElements = true;
					}
                    break;
            }
        }
        /// <summary>
        /// Najde a určí dvě události: fixedEvent je událost ze serveru s vyšší prioritou času, shiftEvent s nižší prioritou. Pak vrací true.
        /// Pokud nejsou vybrány dvě události ze dvou serverů s definovanou a odlišnou prioritou, vrací false.
        /// </summary>
        /// <param name="args"></param>
        /// <param name="fixedEvent"></param>
        /// <param name="shiftEvent"></param>
        /// <returns></returns>
        private bool _GetEvents(FunctionContextMenuItemRunArgs args, out EventInfo fixedEvent, out EventInfo shiftEvent)
        {
            fixedEvent = null;
            shiftEvent = null;
            List<EventInfo> events = this.GetInputEventInfos(args);              // Načte data (EventInfo) pro všechny zadané události
            if (events.Count != 2) return false;

            EventInfo event0 = events[0];
            EventInfo event1 = events[1];
            if (event0.Server.ServerTimePriority.HasValue && event1.Server.ServerTimePriority.HasValue)
            {
                if (event0.Server.ServerTimePriority.Value < event1.Server.ServerTimePriority.Value)
                {
                    fixedEvent = event0;
                    shiftEvent = event1;
                }
                else if (event0.Server.ServerTimePriority.Value > event1.Server.ServerTimePriority.Value)
                {
                    fixedEvent = event1;
                    shiftEvent = event0;
                }
            }
            return (fixedEvent != null && shiftEvent != null);
        }
        #endregion
    }
}
